home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / src / TreeView.C < prev    next >
C/C++ Source or Header  |  1990-12-04  |  12KB  |  536 lines

  1. //$TreeNode,TreeView,TreeNodeSelector$
  2. #include "TreeView.h"
  3. #include "Menu.h"
  4.  
  5. #include "String.h"
  6. #include "OrdColl.h"
  7.  
  8. void Indent(ostream &s, int l)
  9. {
  10.     for (int i= 0; i<l; i++)
  11.     s << " ";
  12. }
  13.  
  14. //---- TreeNode ----------------------------------------------------------------
  15.  
  16. MetaImpl(TreeNode, (TP(treeview), 0));
  17.  
  18. TreeNode::TreeNode(int id,  Collection *cp) : CompositeVObject(id, cp)
  19. {
  20. }
  21.  
  22. TreeNode::TreeNode(int va_(id), ...) : CompositeVObject(va_(id), (Collection*)0)
  23. {
  24.     va_list ap;
  25.     va_start(ap,va_(id));
  26.     SetItems(ap);
  27.     va_end(ap);
  28. }
  29.  
  30. TreeNode::TreeNode(int id, va_list ap) : CompositeVObject(id, ap)
  31. {
  32. }
  33.  
  34. void TreeNode::SetOrigin(Point at)
  35. {
  36.     Iter next(list);
  37.     VObject *dip, *first;
  38.  
  39.     VObject::SetOrigin(at);
  40.     first= (VObject*) next();
  41.  
  42.     if (Collapsed() || Size() == 1)
  43.     first->SetOrigin(at);
  44.     else {
  45.     switch (Layout()) {
  46.     case eTLTopDown:
  47.         first->SetOrigin(at+Point((Width()-first->Width())/2, 0));
  48.         at.y+= Gap().y+first->Height();
  49.         while (dip= (VObject*) next()) {
  50.         dip->SetOrigin(at);
  51.         at.x+= dip->Width()+Gap().x;
  52.         }
  53.         break;
  54.     case eTLIndented:
  55.     case eTLLeftRight:
  56.         if (Layout() == eTLIndented) {
  57.         first->SetOrigin(at);
  58.         at+= Point(Gap().x, first->Height()+Gap().y);
  59.         } else {
  60.         first->SetOrigin(at+Point(0, (Height()-first->Height())/2));
  61.         at.x+= Gap().x+first->Width();
  62.         }
  63.         while (dip= (VObject*) next()) {
  64.         dip->SetOrigin(at);
  65.         at.y+= dip->Height()+Gap().y;
  66.         }
  67.         break;
  68.     }
  69.     }
  70. }
  71.  
  72. void TreeNode::Open(bool mode)
  73. {
  74.     CompositeVObject::Open(mode);
  75.     GetTreeView()->OpenTreeNode(this, mode);    
  76. }
  77.  
  78. void TreeNode::Collapse()
  79. {
  80.     Iter next(MakeIterator());
  81.     VObject *vop;
  82.     next();
  83.     while (vop= (VObject*)next())
  84.     vop->Open(Collapsed());
  85.     InvertFlag(eTreeNodeCollapsed);
  86.     Control(cIdNone, cPartLayoutChanged, 0);
  87. }
  88.  
  89. Metric TreeNode::GetMinSize()
  90. {
  91.     Metric m, m1, mn;
  92.     Iter next(list);
  93.     VObject *dip, *first;
  94.  
  95.     first= (VObject*) next();
  96.  
  97.     if (Collapsed() || Size() == 1)
  98.     return first->GetMinSize();
  99.     m1= first->GetMinSize();
  100.     switch(Layout()) {
  101.     case eTLTopDown:
  102.     while (dip= (VObject*) next()) {
  103.         mn= dip->GetMinSize();
  104.         m.extent.y= max(m.extent.y, mn.extent.y);
  105.         m.extent.x+= mn.extent.x+Gap().x;
  106.     }
  107.     m.extent.x-= Gap().x;
  108.     m.extent.x= max(m.extent.x, m1.extent.x);
  109.     m.extent.y+= m1.extent.y+Gap().y;
  110.     m.base= m.extent.y;
  111.     break;
  112.     case eTLIndented:
  113.     case eTLLeftRight:
  114.     while (dip= (VObject*) next()) {
  115.         mn= dip->GetMinSize();
  116.         m.extent.x= max(m.extent.x, mn.extent.x);
  117.         m.extent.y+= mn.extent.y+Gap().y;
  118.     }
  119.     if (Layout() == eTLIndented) {
  120.         m.extent.y+= m1.extent.y;
  121.         m.extent.x+= Gap().x;
  122.         m.extent.x= max(m.extent.x, m1.extent.x);
  123.         m.base= m1.base;
  124.     } else {
  125.         m.extent.y-= Gap().y;
  126.         m.extent.y= max(m.extent.y, m1.extent.y);
  127.         m.extent.x+= m1.extent.x+Gap().x;
  128.         m.base= m.extent.y;
  129.     }
  130.     break;
  131.     }
  132.     return m;
  133. }
  134.  
  135. int TreeNode::Base()
  136. {
  137.     if (Layout() == eTLIndented)
  138.     return At(0)->Base();
  139.     return CompositeVObject::Base();
  140. }
  141.  
  142. void TreeNode::Draw(Rectangle r)
  143. {
  144.     VObject *sel= GetTreeView()->GetSelection(), *vop;
  145.  
  146.     if (Collapsed()) {
  147.     vop= At(0);
  148.     vop->DrawAll(r, vop == sel);
  149.     GrStrokeRoundRect(contentRect, gPoint10);
  150.     } else {
  151.     if (ConnType() != eTCNone) {
  152.         GrSetPenNormal();
  153.         DrawConnections();
  154.     }
  155.     Iter next(MakeIterator());
  156.     while (vop= (VObject*)next())
  157.         vop->DrawAll(r, vop == sel);
  158.     }
  159. }
  160.  
  161. void TreeNode::DrawConnections()
  162. {
  163.     if (Size() == 1)
  164.     return;
  165.     Iter next(list);
  166.     VObject *dip, *first;
  167.     Point p1, p2;
  168.     int l;
  169.  
  170.     GrSetPenSize(0);
  171.     first= (VObject*) next();
  172.  
  173.     switch (Layout()) {
  174.     case eTLIndented:
  175.     if (ConnType() == eTCPerpendicular) {
  176.         l= Gap().x/2;
  177.         p1= first->contentRect.SW() + Point(l, 0);
  178.         while (dip= (VObject*) next()) {
  179.         p2= dip->contentRect.origin+Point(0, dip->Base()-5);
  180.         GrLine(p2, p2-Point(l,0));
  181.         }
  182.         GrLine(p1, p2-Point(l,0));
  183.     }
  184.     break;
  185.     case eTLTopDown:
  186.     if (ConnType() == eTCPerpendicular || ConnType() == eTCDiagonal2) {
  187.         l= ConnType() == eTCPerpendicular ? Gap().y/2 : 5;
  188.         p1= first->contentRect.S();
  189.         p2= p1+Point(0,l);
  190.         GrLine(p1, p2);
  191.         while (dip= (VObject*) next())
  192.         GrLine(dip->contentRect.N(), dip->contentRect.N()-Point(0,l));
  193.     }
  194.     if (ConnType() == eTCDiagonal || ConnType() == eTCDiagonal2) {
  195.         next.Reset(list);
  196.         first= (VObject*) next();
  197.         l= ConnType() == eTCDiagonal ? 0 : 5;
  198.         p1= first->contentRect.S()+Point(0,l);
  199.  
  200.         while (dip= (VObject*) next())
  201.         GrLine(p1, dip->contentRect.N()-Point(0,l));
  202.     } else {
  203.         l= Gap().y/2;
  204.         p1= At(1)->contentRect.N()-Point(0,l);
  205.         p2= At(Size()-1)->contentRect.N()-Point(0,l);
  206.         GrLine(p1, p2);
  207.     }
  208.     break;
  209.     case eTLLeftRight:
  210.     if (ConnType() == eTCPerpendicular || ConnType() == eTCDiagonal2) {
  211.         l= ConnType() == eTCPerpendicular ? Gap().x/2 : 5;
  212.         p1= first->contentRect.E();
  213.         p2= p1+Point(l,0);
  214.         GrLine(p1, p2);
  215.         while (dip= (VObject*) next())
  216.         GrLine(dip->contentRect.W(), dip->contentRect.W()-Point(l,0));
  217.     }
  218.     if (ConnType() == eTCDiagonal || ConnType() == eTCDiagonal2) {
  219.         next.Reset(list);
  220.         first= (VObject*) next();
  221.         l= ConnType() == eTCDiagonal ? 0 : 5;
  222.         p1= first->contentRect.E()+Point(l,0);
  223.  
  224.         while (dip= (VObject*) next())
  225.         GrLine(p1, dip->contentRect.W()-Point(l,0));
  226.     } else {
  227.         l= Gap().x/2;
  228.         p1= At(1)->contentRect.W()-Point(l,0);
  229.         p2= At(Size()-1)->contentRect.W()-Point(l,0);
  230.         GrLine(p1, p2);
  231.     }
  232.     break;
  233.     }
  234. }
  235.  
  236. void TreeNode::Outline2(Point p1, Point p2)
  237. {
  238.     Rectangle r= NormRect(p1, p2);
  239.     if (Collapsed())
  240.     GrStrokeRoundRect(r, gPoint10);
  241.     else if (Layout() == eTLIndented) {
  242.     Point sw= At(0)->contentRect.SW()+(r.origin-contentRect.origin);
  243.     int gap= Gap().x;
  244.  
  245.     GrLine(r.NW(), r.NE());
  246.     GrLine(r.NE()+Point(0,1), r.SE());
  247. #ifdef sun
  248.     GrLine(r.SE()-Point(1,0), r.SW()+Point(gap,0));
  249. #else
  250.     Point pp= r.SW()+Point(gap,0);
  251.     GrLine(r.SE()-Point(1,0), pp);
  252. #endif
  253.     GrLine(r.SW()+Point(gap,-1), r.NW()+Point(gap, At(0)->Height()));
  254.     GrLine(sw+Point(gap-1,0), sw);
  255.     GrLine(sw-Point(0,1), r.NW());
  256.     } else
  257.     CompositeVObject::Outline2(p1, p2);
  258. }
  259.  
  260. void TreeNode::SetContainer(VObject *vop)
  261. {
  262.     CompositeVObject::SetContainer(vop);
  263.     treeview= (TreeView*)GetView();     // ????
  264. }
  265.  
  266. void TreeNode::Highlight(HighlightState hst)
  267. {
  268.     At(0)->Highlight(hst);
  269. }
  270.  
  271. Command *TreeNode::DispatchEvents(Point lp, Token t, Clipper *vf)
  272. {
  273.     if (At(0)->ContainsPoint(lp))
  274.     return VObject::DispatchEvents(lp, t, vf);
  275.     if (Collapsed())
  276.     return 0;
  277.     return CompositeVObject::DispatchEvents(lp, t, vf);
  278. }
  279.  
  280. Command *TreeNode::DoMiddleButtonDownCommand(Point, Token t, int)
  281. {
  282.     if (t.Flags & eFlgShiftKey) 
  283.     treeview->Promote(this);
  284.     else
  285.     treeview->Collapse(this);
  286.     return gNoChanges;
  287. }
  288.  
  289. Command *TreeNode::DoLeftButtonDownCommand(Point, Token, int cl)
  290. {
  291.     return treeview->GetNodeSelector(this, cl);
  292. }
  293.     
  294. GrCursor TreeNode::GetCursor(Point lp)
  295. {
  296.     if (Collapsed() && At(0)->ContainsPoint(lp))
  297.     return eCrsBoldCross;
  298.     return CompositeVObject::GetCursor(lp);
  299. }
  300.  
  301. void TreeNode::Export(ostream &s, int level)
  302. {    
  303.     Iter next(list);
  304.     TreeNode *tn;
  305.  
  306.     tn= (TreeNode*) next();
  307.     if (tn) {
  308.     Indent(s, level);
  309.     s << tn->AsString() NL;
  310.     while (tn= (TreeNode*) next()) {
  311.         if (tn->IsKindOf(TreeNode))
  312.         tn->Export(s, level+2);
  313.         else {
  314.         Indent(s, level+2);
  315.         s << tn->AsString() NL;
  316.         }
  317.     }
  318.     }
  319. }
  320.  
  321. VObject *TreeNode::Detect(BoolFun f, void *arg)
  322. {
  323.     if (!Collapsed()) {
  324.     VObject *vop= CompositeVObject::Detect(f, arg);
  325.     if (vop && !vop->IsKindOf(TreeNode))
  326.         return vop;
  327.     }
  328.     return 0;
  329. }
  330.  
  331. VObject *TreeNode::FindExpandedItem(VObject *vop)
  332. {
  333.     VObject *op, *found= 0;
  334.     
  335.     Iter next(list);    
  336.     while ((op= (VObject*)next()) && !found) {
  337.     if (op->IsKindOf(TreeNode)) 
  338.         found= ((TreeNode*)op)->FindExpandedItem(vop);
  339.     else
  340.         found= op->FindItem(vop);
  341.     if (Collapsed() && found)
  342.         found= At(0);
  343.     }
  344.     return found;
  345. }
  346.  
  347. //---- TreeNodeSelector ----------------------------------------------------------------
  348.  
  349. TreeNodeSelector::TreeNodeSelector(TreeNode *s, int cl)
  350. {
  351.     item= s;
  352.     lastinside= FALSE;
  353.     clicks= cl;
  354. }
  355.  
  356. void TreeNodeSelector::TrackFeedback(Point, Point, bool)
  357. {
  358.     VObject *image= item->At(0);
  359.     if (item && (lastinside != inside)) {
  360.     item->At(0)->Outline(0);
  361.     lastinside= inside;
  362.     }
  363. }
  364.  
  365. Command *TreeNodeSelector::TrackMouse(TrackPhase atp, Point, Point, Point np)
  366. {
  367.     VObject *image= item->At(0);
  368.     inside= image->ContainsPoint(np);
  369.     if (atp == eTrackRelease) {
  370.     if (item && lastinside) {
  371.         image->Outline(0);
  372.         item->GetTreeView()->SetSelection(image);
  373.         return item->GetTreeView()->NodeSelected(item->At(0), clicks);
  374.     }                
  375.     }
  376.     return this;
  377. }
  378.  
  379. //---- TreeView ----------------------------------------------------------------
  380.  
  381. MetaImpl(TreeView, (TE(layout), TE(connType), TP(tree), TP(selection), 0));
  382.  
  383. TreeView::TreeView(EvtHandler *eh, TreeLayout lt, TreeConnection tc) 
  384.                                 : DialogView(eh)
  385. {
  386.     connType= tc;
  387.     layout= lt;
  388.     gap= Point(30, 4);
  389.     tree= oldtree= 0;
  390.     selection= 0;
  391. }
  392.  
  393. VObject *TreeView::DoCreateDialog()
  394. {
  395.     return new TextItem("root");
  396. }
  397.  
  398. void TreeView::SetLayout(TreeLayout tl)
  399. {
  400.     layout= tl;
  401.     switch (layout) {
  402.     case eTLIndented:
  403.     gap= Point(20, 2);
  404.     break;
  405.     case eTLTopDown:
  406.     gap= Point(10, 40);
  407.     break;
  408.     case eTLLeftRight:
  409.     gap= Point(30, 4);
  410.     break;
  411.     }
  412.     CalcLayout();
  413. }
  414.  
  415. void TreeView::SetConnType(TreeConnection ct)
  416. {
  417.     connType= ct;
  418.     CalcLayout();
  419. }
  420.  
  421. void TreeView::SetTree(TreeNode *t, bool freeold)
  422. {
  423.     if (freeold && tree) {
  424.     tree->FreeAll();
  425.     delete tree;
  426.     }
  427.     SetDialog(tree= t);
  428.     oldtree= 0;
  429. }
  430.  
  431. void TreeView::Promote(TreeNode *newt)
  432. {
  433.     if (oldtree != 0 && newt == tree) {
  434.     SetTree(oldtree, FALSE);
  435.     oldtree= 0;
  436.     } else {
  437.     if (oldtree == 0)
  438.         oldtree= tree;
  439.     SetTree(newt, FALSE);
  440.     }
  441.     ForceRedraw();
  442. }
  443.  
  444. void TreeView::Collapse(TreeNode *tn)
  445. {
  446.     tn->Collapse();
  447. }
  448.  
  449. void TreeView::OpenTreeNode(TreeNode*, bool)
  450. {
  451. }
  452.  
  453. ostream &TreeView::PrintOn(ostream &s)
  454. {
  455.     return s << layout SP << connType SP << gap SP << tree SP;
  456. }
  457.  
  458. istream &TreeView::ReadFrom(istream &s)
  459. {
  460.     s >> Enum(layout) >> Enum(connType) >> gap >> tree;
  461.     SetTree(tree);
  462.     return s;
  463. }
  464.  
  465. void TreeView::Export(ostream &s)
  466. {
  467.     if (tree)
  468.     tree->Export(s, 0);
  469. }
  470.  
  471. VObject *TreeView::FindNode(VObject *gp)
  472. {
  473.     if (tree)
  474.     return tree->FindExpandedItem(gp);
  475.     return 0;
  476. }
  477.  
  478. Command *TreeView::GetNodeSelector(TreeNode *tn, int cl)
  479. {
  480.     return new TreeNodeSelector(tn, cl);
  481. }
  482.  
  483. Command *TreeView::NodeSelected(VObject* vop, int cl)
  484. {
  485.     int partcode= cl >= 2 ? cPartTreeDoubleSelect: cPartTreeSelect;
  486.     Control(GetId(), partcode, (void*) vop);
  487.     return gNoChanges;
  488. }
  489.  
  490. void TreeView::SetSelection(VObject *vop)
  491. {
  492.     if (vop != selection) {
  493.     if (selection)
  494.         selection->ForceRedraw();
  495.     selection= vop;
  496.     if (selection) 
  497.         selection->ForceRedraw();
  498.     }
  499. }
  500.  
  501. VObject *TreeView::BuildTree(Object *op)
  502. {
  503.     VObject *g= NodeAsVObject(op);
  504.     Collection *list= new OrdCollection;
  505.     list->Add(g);
  506.     Iterator *it= MakeChildrenIter(op);
  507.     if (it) {
  508.     Iter next(it); 
  509.     while (op= next()) {
  510.         VObject *newitem= BuildTree(op);
  511.         if (!newitem->IsKindOf(TreeNode))
  512.         newitem= new TreeNode(5, newitem, 0);
  513.         list->Add(newitem);
  514.     }
  515.     }
  516.     g= new TreeNode(4, list);
  517.     return g;
  518. }
  519.  
  520. VObject *TreeView::NodeAsVObject(Object *)
  521. {
  522.     AbstractMethod("AsVObject");
  523.     return 0;  
  524. }
  525.  
  526. Iterator *TreeView::MakeChildrenIter(Object *)
  527. {
  528.     AbstractMethod("GetSubPartsIter");
  529.     return 0;  
  530. }
  531.  
  532. void TreeView::InstallTree(Object *root)
  533. {
  534.     SetTree((TreeNode*)BuildTree(root));    
  535. }
  536.